home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Frameworks / Grant's CGI Framework 1.0b14 / Util / ProcessUtil.c < prev    next >
Text File  |  1996-04-12  |  19KB  |  740 lines

  1. /*****
  2.  *
  3.  *    ProcessUtil.c
  4.  *
  5.  *    This is a support file for "Grant's CGI Framework".
  6.  *    Please see the license agreement that accompanies the distribution package
  7.  *    for licensing details.
  8.  *
  9.  *    Copyright ©1995,1996 by Grant Neufeld
  10.  *    grant@acm.com
  11.  *    http://arpp.carleton.ca/grant/
  12.  *
  13.  *****/
  14.  
  15. #include "MyConfiguration.h"
  16.  
  17. #include <Threads.h>
  18.  
  19. #include "compiler_stuff.h"
  20. #include "globals.h"
  21.  
  22. #include "DebugUtil.h"
  23.  
  24. #include "ProcessUtil.h"
  25.  
  26.  
  27. /***  LOCAL VARIABLES  ***/
  28.  
  29. static short    vAppBusyLevel;        /* how busy the application is */
  30. static UInt32    vSleepTicksDefault;    /* sleep time when app is idle */
  31. static UInt32    vSleepTicksBusy;    /* sleep time when app is processing */
  32.  
  33. static ThreadID    vThreadMain;        /* main application thread id */
  34. static Boolean    vThreadMainIsAsleep;
  35.  
  36. #if kCompileWithDeferredTask
  37. static ThreadID    vDeferredTaskThread;
  38. #endif
  39. //static ThreadID    vThreadStatusUpdate;
  40.  
  41. /* an array of sleeping thread IDs */
  42. #if kStartupThreadsPreallocate > nil
  43. static ThreadID    vThreadSleepers[kStartupThreadsPreallocate]; /* array of sleepers */
  44. static ThreadID vThreadSleeperHead;        /* next thread to wake up */
  45. static ThreadID vThreadSleeperAddHere;    /* next open spot in queue */
  46. static short    vThreadSleepersTotal;    
  47. #endif
  48.  
  49.  
  50. /***  LOCAL PROTOTYPES  ***/
  51.  
  52. pascal void        threadTermination            ( ThreadID, void * );
  53. pascal void *    threadDeferredTaskThread    ( void * );
  54. static void        threadSleepersInit            ( void );
  55.  
  56.  
  57. /***  FUNCTIONS  ***/
  58.  
  59. /*  */
  60. void
  61. ProcessStartup ( void )
  62. {
  63.     ProcessSleepSetDefault ( kSleepTicks );
  64.     ProcessSleepSetBusy    ( kSleepTicksWhenBusy );
  65.     ProcessSleepDefault    ();
  66.     
  67.     /* we're not busy yet */
  68.     vAppBusyLevel = nil;
  69.     
  70.     gFrontProcess = ProcessCurrentIsFront ();
  71.     
  72.     #if kCompileWithProcessFileSpec
  73.     ProcessGetMyFSSpec ( &gProcessFSSpec );
  74.     #endif
  75. } /* ProcessStartup */
  76.  
  77.  
  78. /* Give time for other processes (both internal to the app and other applications) */
  79. p_export
  80. void
  81. ProcessGiveTime ( UInt32 sleepTicks )
  82. {
  83.     OSErr            theErr;
  84.     #if kCompileWithThreadsOptional
  85.     EventRecord        theEvent;
  86.     
  87.     if ( gHasThreadMgr )
  88.     {
  89.     #endif
  90.         
  91.         theErr = ThreadYield ( nil, true );
  92.         
  93.     #if kCompileWithThreadsOptional
  94.     }
  95.     else
  96.     {
  97.         if ( sleepTicks > nil )
  98.         {
  99.             /* if sleepTicks is a 'usable' value, use it */
  100.             WaitNextEvent ( nil, &theEvent, sleepTicks, NULL );
  101.         }
  102.         else
  103.         {
  104.             /* otherwise, use the current application sleep ticks setting */
  105.             WaitNextEvent ( nil, &theEvent, gSleepTicks, NULL );
  106.         }
  107.     }
  108.     #endif
  109. } /* ProcessGiveTime */
  110.  
  111.  
  112. /* Determine if the current application is active (is in front of all others) */
  113. Boolean
  114. ProcessCurrentIsFront ( void )
  115. {
  116.     #if kCompileWithForeground
  117.     
  118.     Boolean                    isFront;
  119.     ProcessSerialNumber        myPSN;
  120.     OSErr                    theErr;
  121.     
  122.     /* get my process serial number. IM:Processes 2-21 */
  123.     theErr = GetCurrentProcess ( &myPSN );
  124.     if ( theErr != noErr )
  125.     {
  126.         /* might want to do something else here to handle the error */
  127.         return false;
  128.     }
  129.     
  130.     isFront = ProcessIsFront ( &myPSN );
  131.     
  132.     return isFront;
  133.     
  134.     #else    /* if not kCompileWithForeground */
  135.     
  136.     return false;
  137.     
  138.     #endif    /* kCompileWithForeground */
  139. } /* ProcessCurrentIsFront */
  140.  
  141.  
  142. /* Run through WaitNextEvent, not handling events, until the process comes
  143.     to the foreground.
  144.     Returns false if timeout is reached before process brought to front.
  145.     Timeout is in ticks (60ths of a second). If timeout is nil - doesn't timeout. */
  146. Boolean
  147. ProcessWaitUntilFront ( unsigned long timeout )
  148. {
  149.     #if kCompileWithForeground
  150.     Boolean            isFront;
  151.     long            endTime;
  152.     long            sleepTicks;
  153.     
  154.     isFront = ProcessCurrentIsFront ();
  155.     if ( !isFront )
  156.     {
  157.         endTime = TickCount() + timeout;
  158.         
  159.         if ( (timeout > 20) || (timeout == nil) )
  160.         {
  161.             sleepTicks = 20;
  162.         }
  163.         else
  164.         {
  165.             sleepTicks = timeout;
  166.         }
  167.         
  168.         do
  169.         {
  170.             ProcessGiveTime ( sleepTicks );
  171.             
  172.             isFront = ProcessCurrentIsFront ();
  173.         } while ( !isFront && ((timeout == nil) || (endTime >= TickCount())) );
  174.     }
  175.     
  176.     return isFront;
  177.     
  178.     #else
  179.         /* can't be in foreground/front if application is background only */
  180.         return false;
  181.     #endif /* kCompileWithForeground */
  182. } /* ProcessWaitUntilFront */
  183.  
  184.  
  185. /* Determine if the specified application is active (is in front of all others) */
  186. Boolean
  187. ProcessIsFront ( ProcessSerialNumber *thePSN )
  188. {
  189.     #if kCompileWithForeground
  190.     OSErr                    theErr;
  191.     ProcessSerialNumber        frontPSN;
  192.     
  193.     my_assert ( thePSN != NULL, "\pProcessIsFront: thePSN ptr is NULL" );
  194.     
  195.     theErr = GetFrontProcess ( &frontPSN );
  196.     if ( theErr != noErr )
  197.     {
  198.         /* might want to do something else here to handle the error */
  199.         return false;
  200.     }
  201.     
  202.     return ( (frontPSN.lowLongOfPSN == thePSN->lowLongOfPSN) &&
  203.         (frontPSN.highLongOfPSN == thePSN->highLongOfPSN) );
  204.     
  205.     #else
  206.         /* can't be in foreground/front if application is background only */
  207.         return false;
  208.     #endif /* kCompileWithForeground */
  209. } /* ProcessIsFront */
  210.  
  211.  
  212. /* Fill out an already allocated FSSpec with the current process' location.
  213.     Thanks to Gregory S. Combs for providing most of this function. */
  214. OSErr
  215. ProcessGetMyFSSpec ( FSSpec *procFileSpec )
  216. {
  217.     OSErr                    theErr;
  218.     ProcessSerialNumber        curPSN;
  219.     ProcessInfoRec            procInfo;
  220.     Str255                    appName;
  221.     
  222.     my_assert ( procFileSpec != NULL, "\pProcessGetMyFSSpec: procFileSpec ptr is NULL" );
  223.     
  224.     theErr = GetCurrentProcess ( &curPSN );
  225.     if ( theErr == noErr )
  226.     {
  227.         procInfo.processInfoLength    = sizeof ( ProcessInfoRec );
  228.         procInfo.processName        = appName;
  229.         procInfo.processAppSpec        = procFileSpec;
  230.         
  231.         theErr = GetProcessInformation ( &curPSN, &procInfo );
  232.     }
  233.     
  234.     return theErr;
  235. } /* ProcessGetMyFSSpec */
  236.  
  237.  
  238. /**  BUSY LEVEL and SLEEP TICKS  **/
  239. #pragma mark -
  240.  
  241. /* The 'busy' level of the application affects how much time it will try to
  242.     grab for processing */
  243.  
  244. /*  */
  245. p_export
  246. void
  247. ProcessIsMoreBusy ( void )
  248. {
  249.     OSErr    theErr;
  250.     
  251.     if ( vAppBusyLevel == nil )
  252.     {
  253.         /* we weren't busy, so need to move into busy state */
  254.         /* adjust the sleepTicks */
  255.         ProcessSleepBusy ();
  256.         /* put the deferredTasks thread to sleep */
  257.         #if kCompileWithDeferredTask
  258.         if ( vDeferredTaskThread != nil )
  259.         {
  260.             theErr = SetThreadState ( vDeferredTaskThread, kStoppedThreadState, nil );
  261.         }
  262.         #endif
  263.     }
  264.     vAppBusyLevel++;
  265. } /* ProcessIsMoreBusy */
  266.  
  267. /*  */
  268. p_export
  269. void
  270. ProcessIsLessBusy ( void )
  271. {
  272.     OSErr    theErr;
  273.     
  274.     vAppBusyLevel--;
  275.     if ( vAppBusyLevel == nil )
  276.     {
  277.         /* we're no longer busy, so need to move into non-busy state */
  278.         /* adjust the sleepTicks */
  279.         ProcessSleepDefault ();
  280.         /* wake up the deferredTasks thread */
  281.         #if kCompileWithDeferredTask
  282.         if ( vDeferredTaskThread != nil )
  283.         {
  284.             theErr = SetThreadState ( vDeferredTaskThread, kReadyThreadState, nil );
  285.         }
  286.         #endif
  287.     }
  288. } /* ProcessIsLessBusy */
  289.  
  290.  
  291. /* sleepTicks is used to determine how much time to give for other processes
  292.     to use. */
  293.  
  294. /* set the number of ticks used for normal sleep time */
  295. p_export
  296. void
  297. ProcessSleepSetDefault ( UInt32 sleepTicks )
  298. {
  299.     vSleepTicksDefault = sleepTicks;
  300. } /* ProcessSleepSetDefault */
  301.  
  302. /* set the number of ticks used for busy sleep time */
  303. p_export
  304. void
  305. ProcessSleepSetBusy ( UInt32 sleepTicks )
  306. {
  307.     vSleepTicksBusy = sleepTicks;
  308. } /* ProcessSleepSetBusy */
  309.  
  310. /* Call this when app becmoes not busy */
  311. p_export
  312. void
  313. ProcessSleepDefault ( void )
  314. {
  315.     gSleepTicks = vSleepTicksDefault;
  316. } /* ProcessSleepDefault */
  317.  
  318. /* Call this when app becmoes busy */
  319. p_export
  320. void
  321. ProcessSleepBusy ( void )
  322. {
  323.     gSleepTicks = vSleepTicksBusy;
  324. } /* ProcessSleepBusy */
  325.  
  326.  
  327. /**  THREAD FUNCTIONS  **/
  328. #pragma mark -
  329.  
  330. void
  331. ThreadStartup ( void )
  332. {
  333.     OSErr    theErr;
  334.     long    feature;
  335.     
  336.     #if kCompileWithThreadsOptional
  337.     gHasThreadMgr = false;
  338.     #endif
  339.     
  340.     theErr = Gestalt ( gestaltThreadMgrAttr, &feature );
  341.     if ( theErr == noErr )
  342.     {
  343.         if (
  344.             #ifdef powerc
  345.             ( feature & (1 << gestaltThreadsLibraryPresent) ) &&
  346.             /* ••• Can anybody who does PowerPC code tell me why the following
  347.                 line doesn't work?
  348.                 ( (Ptr)NewThread != kUnresolvedSymbolAddress ) &&
  349.                 ••• */
  350.             #endif /* def powerc */
  351.             /* the feature check applies to both 68K & PPC */
  352.             ( feature & (1 << gestaltThreadMgrPresent) ) )
  353.         {
  354.             #if kCompileWithThreadsOptional
  355.             gHasThreadMgr = true;
  356.             #endif
  357.             
  358.             gThreadQuit = false;
  359.             
  360.             /* no sub threads running yet */
  361. //            #if kStartupThreadsPreallocate > nil
  362.             gThreadTotal = nil;
  363. //            /* no sleeping thread yet */
  364. //            gThreadSleeperIndex = 0;
  365. //            gThreadSleeper = nil;
  366. //            #endif
  367.             
  368.             /* determine the id of the main (current) thread */
  369.             GetCurrentThread ( &vThreadMain );
  370.             vThreadMainIsAsleep = false;
  371.             
  372.             #if (kStartupThreadsPreallocate > nil)
  373.             /* pre-allocate the required number of threads */
  374.             CreateThreadPool ( kCooperativeThread, kStartupThreadsPreallocate, nil );
  375.             
  376.             threadSleepersInit ();
  377.             #endif
  378.             
  379.             /* create the deferred tasks thread */
  380.             #if kCompileWithDeferredTask
  381.             theErr = ThreadNewThreadFromPool ( threadDeferredTaskThread,
  382.                 (void *)NULL, (void**)NULL, &vDeferredTaskThread );
  383.             #endif
  384.         }
  385.     }
  386. } /* ThreadStartup */
  387.  
  388.  
  389. /* you should always make sure that your sub-threads can't get 'stuck' in a loop.
  390.     They should, at the very least, check gThreadQuit periodically so that the
  391.     application can quit without getting hung on threads that won't go away. */
  392.  
  393.  
  394. /* Allocate a new thread from the existing pool of threads.
  395.     If there are no threads available, yield to other threads until one finishes.
  396.     The Thread Manager must be available for this function to work. */
  397. #if kStartupThreadsPreallocate > nil
  398. p_export
  399. OSErr
  400. ThreadNewThreadFromPool (
  401.     ThreadEntryProcPtr    threadEntry,
  402.     void *                threadParam,
  403.     void **                threadResult,
  404.     ThreadID *            threadMade )
  405. {
  406.     OSErr        theErr;
  407.     short        threadsFree;
  408.     ThreadID    currentThread;
  409.     
  410.     #if kCompileWithThreadsOptional
  411.     my_assert ( gHasThreadMgr, "\pThreadNewThreadFromPool: Thread Manager not available" );
  412.     #endif
  413.     
  414.     theErr = GetFreeThreadCount ( kCooperativeThread, &threadsFree );
  415.     if ( theErr == noErr )
  416.     {
  417.         theErr = GetCurrentThread ( ¤tThread );
  418.     }
  419.     
  420.     if ( (theErr == noErr) && (threadsFree == nil) )
  421.     {
  422.         /* Put the current thread to sleep, to be woken up when a thread
  423.             becomes available. */
  424.         theErr = ThreadSleep ( currentThread );
  425.     }
  426.     
  427.     if ( theErr == noErr )
  428.     {
  429.         /* Install the new thread using a premade thread from the pool. */
  430.         theErr = NewThread ( kCooperativeThread, threadEntry, threadParam, nil,
  431.             kFPUNotNeeded + kUsePremadeThread, threadResult, threadMade );
  432.     }
  433.     
  434.     if ( theErr == noErr )
  435.     {
  436.         /* set the termination function for the thread. */
  437.         SetThreadTerminator ( *threadMade, threadTermination, NULL );
  438.         
  439.         /* increment the total number of sub-threads. */
  440.         ++gThreadTotal;
  441.     }
  442.     
  443.     return theErr;
  444. } /* ThreadNewThreadFromPool */
  445. #endif
  446.  
  447.  
  448. /* The Thread Manager must be available for this function to work. */
  449. #if kStartupThreadsPreallocate > nil
  450. pascal void
  451. threadTermination ( ThreadID threadTerminated, void *terminationProcParam )
  452. {
  453.     OSErr    theErr;
  454.     
  455.     #if kCompileWithThreadsOptional
  456.     my_assert ( gHasThreadMgr, "\pmyThreadTermination: Thread Manager not available" );
  457.     #endif
  458.     my_assert ( gThreadTotal > nil, "\pmyThreadTermination: gThreadTotal is too small" );
  459.     
  460.     /* if there are sleeping threads, wake one up since this one will be disposed */
  461.     theErr = ThreadWakeNext ();
  462.     
  463.     /* Lower the count of sub-threads. */
  464.     --gThreadTotal;
  465. } /* threadTermination */
  466. #endif
  467.  
  468.  
  469. /* Call this instead of YieldToAnyThread.
  470.     suggestThread is the suggested (but not required) thread to yield to next. */
  471. p_export
  472. OSErr
  473. ThreadYield ( ThreadID suggestThread, Boolean useWNE )
  474. {
  475.     OSErr        theErr;
  476.     #if kStartupThreadsPreallocate > nil
  477.     EventRecord    theEvent;
  478.     #endif
  479.     
  480.     #if kCompileWithThreadsOptional
  481.     my_assert ( gHasThreadMgr, "\pThreadYield: Thread Manager not available" );
  482.     #endif
  483.     
  484.     theErr = YieldToAnyThread ();
  485.     
  486.     /* if there's a sleeping thread, it's probably the main thread, so we'll
  487.         need to give time to other apps to process */
  488.     #if kStartupThreadsPreallocate > nil
  489.     if ( useWNE && (vThreadSleepersTotal > nil) )
  490.     {
  491.         WaitNextEvent ( nil, &theEvent, gSleepTicks, NULL );
  492.     }
  493.     #endif
  494.     
  495.     return theErr;
  496. } /* ThreadYield */
  497.  
  498.  
  499. /* Give all sub-threads a chance to finish */
  500. #if (kStartupThreadsPreallocate > nil)
  501. void
  502. ThreadFinishAllSubThreads ( void )
  503. {
  504.     OSErr        theErr;
  505.     ThreadID    currentThread;
  506.     
  507.     #if kCompileWithThreadsOptional
  508.     my_assert ( gHasThreadMgr, "\pThreadFinishAllSubThreads: Thread Manager not available" );
  509.     #endif
  510.     
  511.     theErr = GetCurrentThread ( ¤tThread );
  512.     if ( currentThread != vThreadMain )
  513.     {
  514.         /* lower the count of sub-threads to prevent this sub-thread from
  515.             preventing the exit of the while loop below */
  516.         --gThreadTotal;
  517.     }
  518.     
  519.     gThreadQuit = true;
  520.     
  521.     while ( gThreadTotal > nil )
  522.     {
  523.         if ( gThreadTotal <= vThreadSleepersTotal )
  524.         {
  525.             /* remaining threads are sleeping, so wake one up */
  526.             ThreadWakeNext ();
  527.         }
  528.         
  529.         /* while there remain other threads (not including the current and main),
  530.             let them finish before quitting */
  531.         ProcessGiveTime ( nil );
  532.     }
  533.     
  534.     if ( currentThread != vThreadMain )
  535.     {
  536.         /* increase the count of sub-threads */
  537.         ++gThreadTotal;
  538.     }
  539. } /* ThreadFinishAllSubThreads */
  540. #endif
  541.  
  542.  
  543. /**  Deferred Tasks (low-priority) thread  **/
  544. #pragma mark -
  545. #if kCompileWithDeferredTask
  546.  
  547. /*  */
  548. pascal void *
  549. threadDeferredTaskThread ( void *threadParam )
  550. {
  551.     ThreadID    currentThread;
  552.     
  553.     #if kCompileWithThreadsOptional
  554.     my_assert ( gHasThreadMgr, "\pthreadDeferredTaskThread: Thread Manager not available" );
  555.     #endif
  556.     
  557.     /* continually call CustomDeferredTask until it is time to quit */
  558.     while ( !gThreadQuit )
  559.     {
  560.         CustomDeferredTask ();
  561.         ProcessGiveTime ( nil );
  562.     }
  563.     
  564.     /* Find the ID of current thread and use DisposeThread to dispose of it so
  565.         that my custom thread termination procedure will be used to recycle
  566.         this thread's allocation for the thread pool. */
  567.     GetCurrentThread ( ¤tThread );
  568.     DisposeThread ( currentThread, (void *)noErr, true );
  569.     
  570.     /* This line below is actually irrelevant, since the DisposeThread call above
  571.         will result in the immediate termination of this thread.
  572.         I keep it in because a return result is needed for the compiler not to
  573.         issue a warning (and I have the "treat all warnings as errors" flag set
  574.         in my compiler, like every programmer should). */
  575.     return (void *)noErr;
  576. } /* threadDeferredTaskThread */
  577.  
  578. #endif /* kCompileWithDeferredTask */
  579.  
  580.  
  581. /**  SLEEPING THREADS  **/
  582. #pragma mark -
  583. #if kStartupThreadsPreallocate > nil
  584. /* this section takes care of dealing with putting threads to sleep, waking
  585.     them up, and keeping track of the sleeping threads.
  586.     It only really applies to situations when resources are tied up and a
  587.     thread can't proceed until some resources become available. In particular,
  588.     when allocating new threads from the pool of preallocated threads, if the
  589.     pool contains no unused threads, the thread attempting to allocate can go
  590.     to sleep until some other thread quits resulting in a thread becoming
  591.     available.
  592.     If you want to be able to put a specific thread to sleep and later wake it
  593.     up under specific circumstances (where you don't want to rely on the queue
  594.     to wake it up because it might be woken too early or too late), you will
  595.     have to handle the sleeping and waking on your own (don't touch the
  596.     sleeping threads queue implemented in this module.
  597.     I've implemented a queue (vThreadSleepers) to track the sleeping threads;
  598.     it stores the ThreadIDs which can then be used to wake up the threads on
  599.     a FIFO (first in first out) basis.
  600.     The position for where to add threads to the queue (as they are put to
  601.     sleep) is tracked in vThreadSleeperAddHere.
  602.     The position for where the next thread to wake is in the queue is
  603.     tracked in vThreadSleeperHead.
  604.     The first item in the vThreadSleepers array is identified as 0 (zero),
  605.     and the last is identified by kStartupThreadsPreallocate - 1. */
  606.  
  607. /*  */
  608. static void
  609. threadSleepersInit ( void )
  610. {
  611.     short    counter;
  612.     
  613.     #if kCompileWithThreadsOptional
  614.     my_assert ( gHasThreadMgr, "\pthreadSleepersInit: Thread Manager not available" );
  615.     #endif
  616.     
  617.     for ( counter = 0; counter < kStartupThreadsPreallocate; counter++ )
  618.     {
  619.         vThreadSleepers[counter] = nil;
  620.     }
  621.     vThreadSleeperHead    = nil;
  622.     vThreadSleeperAddHere = nil;
  623.     vThreadSleepersTotal  = nil;
  624. } /* threadSleepersInit */
  625.  
  626.  
  627. /*  */
  628. p_export OSErr
  629. ThreadSleep ( ThreadID theThread )
  630. {
  631.     OSErr    theErr;
  632.     
  633.     #if kCompileWithThreadsOptional
  634.     my_assert ( gHasThreadMgr, "\pThreadSleep: Thread Manager not available" );
  635.     #endif
  636.     my_assert ( theThread != nil, "\pThreadSleep: theThread is nil" );
  637.     
  638.     if ( vThreadSleepersTotal == kStartupThreadsPreallocate )
  639.     {
  640.         /* cannot put all of the application threads to sleep, at least one
  641.             must be running! */
  642.         theErr = true; /* ••• this should be a more meaningful error value */
  643.     }
  644.     else
  645.     {
  646.         my_assert ( vThreadSleepers[vThreadSleeperAddHere] == nil,
  647.             "\pThreadSleep: the AddHere spot in the vThreadSleepers queue is not nil" );
  648.         
  649.         if ( theThread == vThreadMain )
  650.         {
  651.             /* we're putting the main thread to sleep */
  652.             vThreadMainIsAsleep = true;
  653.         }
  654.         
  655.         /* add the threadID to the queue */
  656.         vThreadSleepers[vThreadSleeperAddHere] = theThread;
  657.         /* adjust the index to the next open spot in the queue */
  658.         ++vThreadSleeperAddHere;
  659.         if ( vThreadSleeperAddHere >= kStartupThreadsPreallocate )
  660.         {
  661.             vThreadSleeperAddHere = 0;
  662.         }
  663.         /* we've got one more sleeping thread, now */
  664.         ++vThreadSleepersTotal;
  665.         
  666.         /* this is the call to put the thread to sleep */
  667.         theErr = SetThreadState ( theThread, kStoppedThreadState, nil );
  668.     }
  669.     
  670.     return theErr;
  671. } /* ThreadSleep */
  672.  
  673.  
  674. /* Waking up a thread does not mean that it will immediately start processing,
  675.     it just means that the thread will be back in the set of threads that can
  676.     be yielded to when ThreadYield is called. */
  677. p_export
  678. OSErr
  679. ThreadWakeNext ( void )
  680. {
  681.     OSErr        theErr;
  682.     ThreadID    theThread;
  683.     
  684.     #if kCompileWithThreadsOptional
  685.     my_assert ( gHasThreadMgr, "\pThreadWakeNext: Thread Manager not available" );
  686.     #endif
  687.     
  688.     /* extract the threadID from the queue */
  689.     theThread = vThreadSleepers[vThreadSleeperHead];
  690.     
  691.     if ( theThread == nil )
  692.     {
  693.         /* no sleeping threads */
  694.         theErr = true; /* ••• need better error value here */
  695.     }
  696.     else
  697.     {
  698.         if ( theThread == vThreadMain )
  699.         {
  700.             /* we're waking up the main thread */
  701.             vThreadMainIsAsleep = false;
  702.         }
  703.         
  704.         /* adjust the index of the head of the queue to the next in line */
  705.         vThreadSleepers[vThreadSleeperHead] = nil;
  706.         ++vThreadSleeperHead;
  707.         if ( vThreadSleeperHead >= kStartupThreadsPreallocate )
  708.         {
  709.             vThreadSleeperHead = nil;
  710.         }
  711.         /* we've got one less sleeping thread, now */
  712.         --vThreadSleepersTotal;
  713.         
  714.         /* this is the call to wake up the thread */
  715.         theErr = SetThreadState ( theThread, kReadyThreadState, nil );
  716.     }
  717.     
  718.     return theErr;
  719. } /* ThreadWakeNext */
  720.  
  721.  
  722. /*  */
  723. void
  724. ThreadWakeAll ( ThreadID theThread )
  725. {
  726.     #if kCompileWithThreadsOptional
  727.     my_assert ( gHasThreadMgr, "\pThreadWakeAll: Thread Manager not available" );
  728.     #endif
  729.     
  730.     while ( vThreadSleepersTotal > nil )
  731.     {
  732.         ThreadWakeNext ();
  733.     }
  734. } /* ThreadWakeAll */
  735.  
  736. #endif /* kStartupThreadsPreallocate > nil */
  737.  
  738.  
  739. /*****  EOF  *****/
  740.